package com.vf.cloud.paas.app.agent.common.client.hander;

import java.util.HashMap;
import java.util.Map;

import com.alibaba.fastjson.JSONObject;
import com.jfinal.kit.JsonKit;
import com.jfinal.kit.StrKit;
import com.vf.cloud.paas.app.agent.mvc.service.IRender;
import com.vf.cloud.paas.common.cirrus.Cirrus;
import com.vf.cloud.paas.common.util.R;
import com.vf.cloud.paas.common.vo.ROrder;
import io.netty.channel.*;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class Handler extends SimpleChannelInboundHandler<Object> {
	
	
	private IRender renderImpl;
	private WebSocketClientHandshaker handshaker;
	private ChannelPromise handshakeFuture;
	

	public Handler(IRender renderImpl) {
		super();
		this.renderImpl = renderImpl;
	}

	@Override
	public void channelActive(ChannelHandlerContext channelHandlerContext) {
		handlerAdded(channelHandlerContext);
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
		ctx.close();
	}
	

	public void setHandshaker(WebSocketClientHandshaker handshaker) {
		this.handshaker = handshaker;
	}

	public void handlerAdded(ChannelHandlerContext ctx) {
		this.handshakeFuture = ctx.newPromise();
	}

	public ChannelFuture handshakeFuture() {
		return this.handshakeFuture;
	}

	protected void channelRead0(ChannelHandlerContext ctx, Object o) throws Exception {
		// 握手协议返回，设置结束握手
		if (!this.handshaker.isHandshakeComplete()) {
			FullHttpResponse response = (FullHttpResponse) o;
			this.handshaker.finishHandshake(ctx.channel(), response);
			this.handshakeFuture.setSuccess();
			return;
		} else if (o instanceof TextWebSocketFrame) {

			TextWebSocketFrame textWebSocketFrame = (TextWebSocketFrame) o;
			JSONObject rawMsg = null;
			try {
				rawMsg = JSONObject.parseObject(textWebSocketFrame.text());
			} catch (Exception e) {
				e.printStackTrace();
				log.error(String.format("[%s]>> cannot parse Pass message:%s", 1008, e));
				ctx.close();
			}
			if (rawMsg == null) {
				return;
			}

			if (!rawMsg.containsKey("type")) {
				log.error("Invalid Pass message:" + textWebSocketFrame.text());
				return;
			}
			
			
			String type = rawMsg.getString("type");
			if (StrKit.equals(type, "pong")) {
				return;
			}
			else if(StrKit.equals(type, "unauthorized")) {
				log.info(rawMsg.getString("message"));
			}
			else if(StrKit.equals(type, "NotAvailable")) {
				log.info(rawMsg.getString("message"));
			}
			else if(StrKit.equals(type, "connected")) {
				log.info(rawMsg.getString("message"));
				Cirrus.renderClient.sendGpuInfos();
			}
			else if(StrKit.equals(type, "onGPUInfo")) {
			}
			else if(StrKit.equals(type, "StartClient")) {
				String uuid=rawMsg.getString("uuid");
				R<ROrder> r=renderImpl.AnyOrder(rawMsg);
				Map<String, Object> clientConfig = new HashMap<String, Object>();
				clientConfig.put("type", "onStartClient");
				clientConfig.put("time", System.currentTimeMillis());
				clientConfig.put("r",r);
				clientConfig.put("uuid",uuid);
				send(ctx, JsonKit.toJson(clientConfig));
			}
			else if(StrKit.equals(type, "onGPUInit")) {
				
			}
			else {
				log.error(String.format("unsupported Pass message type:%s", type));
				ctx.close();
			}

		}
		ctx.flush();
	}

	@Override
	public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
		if (evt instanceof IdleStateEvent) {
			IdleStateEvent event = (IdleStateEvent) evt;
			if (event.state().equals(IdleState.READER_IDLE)) {
				sendPing(ctx, System.currentTimeMillis());
			} else if (event.state().equals(IdleState.WRITER_IDLE)) {
				sendPing(ctx, System.currentTimeMillis());
			} else if (event.state().equals(IdleState.ALL_IDLE)) {
				sendPing(ctx, System.currentTimeMillis());
			}
		}
	}
	
	
	public void sendPing(ChannelHandlerContext ctx, long currentTimeMillis) {
		Map<String, Object> clientConfig = new HashMap<String, Object>();
		clientConfig.put("type", "ping");
		clientConfig.put("time", currentTimeMillis);
		send(ctx, JsonKit.toJson(clientConfig));
	}
	
	public void send(ChannelHandlerContext ctx, String json) {
		if (ctx != null) {
			ctx.channel().writeAndFlush(new TextWebSocketFrame(json)).addListener(new ChannelFutureListener() {
				@Override
				public void operationComplete(ChannelFuture future) throws Exception {
					if (future.isSuccess()) {
						// log.info(String.format("-> Streamer:%s", json));
					} else {
						// log.info(String.format("-> Streamer isError :%s", json));
					}
				}
			});
		}
	}

	

}